#include <lcthw/list.h>
#include <lcthw/dbg.h>

List *List_create()
{
    return calloc(1, sizeof(List));
}

void List_destroy(List *list)
{
    LIST_FOREACH(list, first, next, cur) {
        if(cur->prev) {
            free(cur->prev);
        }
    }

    free(list->last);
    free(list);
}


void List_clear(List *list)
{
    LIST_FOREACH(list, first, next, cur) {
        free(cur->value);
    }
}


void List_clear_destroy(List *list)
{
    LIST_FOREACH(list, first, next, cur) {
        free(cur->prev->value);   
        if(cur->prev) {

            free(cur->prev);
        
        }
    }
    free(list->last);

    free(list);
}


void List_push(List *list, void *value)
{
    ListNode *node = calloc(1, sizeof(ListNode));
    check_mem(node);

    node->value = value;

    if(list->last == NULL) {
        list->first = node;
        list->last = node;
    } else {
        list->last->next = node;
        node->prev = list->last;
        list->last = node;
    }

    list->count++;

error:
    return;
}

void *List_pop(List *list)
{
    ListNode *node = list->last;
    return node != NULL ? List_remove(list, node) : NULL;
}

void List_unshift(List *list, void *value)
{
    ListNode *node = calloc(1, sizeof(ListNode));
    check_mem(node);

    node->value = value;

    if(list->first == NULL) {
        list->first = node;
        list->last = node;
    } else {
        node->next = list->first;
        list->first->prev = node;
        list->first = node;
    }

    list->count++;

error:
    return;
}

void *List_shift(List *list)
{
    ListNode *node = list->first;
    return node != NULL ? List_remove(list, node) : NULL;
}

void *List_remove(List *list, ListNode *node)
{
    void *result = NULL;

    check(list->first && list->last, "List is empty.");
    check(node, "node can't be NULL");

    if(node == list->first && node == list->last) {
        list->first = NULL;
        list->last = NULL;
    } else if(node == list->first) {
        list->first = node->next;
        check(list->first != NULL, "Invalid list, somehow got a first that is NULL.");
        list->first->prev = NULL;
    } else if (node == list->last) {
        list->last = node->prev;
        check(list->last != NULL, "Invalid list, somehow got a next that is NULL.");
        list->last->next = NULL;
    } else {
        ListNode *after = node->next;
        ListNode *before = node->prev;
        after->prev = before;
        before->next = after;
    }

    list->count--;
    result = node->value;
    free(node);

error:
    return result;
}

/****** TODO  *****/
List *List_copy(List *  listold){
    List *listnew = List_create();
    LIST_FOREACH(listold, first, next, cur) {
    List_push(listnew,cur->value);
    }
    check_mem(listnew);

    return listnew;

error:
    return;
}

void *List_join(List *  list1,List * list2){
    list1->last->next = list2->first;
    list2->first->prev = list1->last;
    list1->last = list2->last;
    check_mem(list1);
error:
    return;
}
// pos 表示从哪个节点断开
List *List_split(List *  list, int pos){
//    check(pos >= list->count || pos <= 0 , "pos does not meet requirements.");
    List *listnew = List_create();
    ListNode *cur = list->first;
    int i=0;
    while(i < pos)
    {
        cur = cur->next;
        i++;
    }
    listnew->first = cur;
    listnew->last  = list->last; 
    listnew->count = list->count - i;

    list->last     = cur->prev; 
    list->last->next = NULL;
    list->count    = i;

    check_mem(listnew);
    return listnew;
error:
    return;
}


